using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.ComponentModel;

namespace Cephei.Core
{
    /// <summary>
    /// generalised ICell is the base interface for ICell&lt;T&gt; that holds change notification behaviour
    /// </summary>
    public interface ICell : IDisposable
    {
        void Lock ();
        void Unlock ();
        event CellChange Change;
        void OnChange (CellEventType eventType, ICell root, DateTime epoch, ITransaction transaction);
        event CellSink Sink;
        void OnSink (CellSinkEventType eventType, ICell Sender, TimeSpan span);
        bool HasListeners { get; }
        // The parent property provides for instruments to be composed of a number of cells
        IModel Parent { get; set; }
        String Mnmonic { get; set; }
        ITransaction Transaction { get; set; }
        CellMethod Method { get; }
        DateTime Epoch { get; }
        /// <summary>
        /// get the value of the Cell in a generic form
        /// </summary>
        object BoxValue { get; }

        /// <summary>
        /// Transfer any subscriptions from this object to the new destination object 
        /// </summary>
        /// <param name="destination">the recipient of change subscriptions</param>
        void TransferTo (ICell destination);


        /// <summary>
        /// Cells that depend on this cell
        /// </summary>
        ICell[] Dependants { get; }

        /// <summary>
        /// Cells that depend on this cell
        /// </summary>
        ICell[] References { get; }

        /// <summary>
        /// Owner identifier when used with Excel RTD interface
        /// </summary>
        object Owner { get; set; }
    }

    /// <summary>
    /// provide interface for the pre-conditions to the evaluation of a cell
    /// </summary>
    /// <remarks>
    /// added to support the dull Quantlib notion of global observable values
    /// </remarks>
    public interface IPreCell
    {
        /// <summary>
        /// fluent function to apply the pre-condition and then return the value from the cell
        /// </summary>
        /// <typeparam name="T">type of the cell passed in</typeparam>
        /// <param name="cell">value to be taken after pre-condition</param>
        /// <returns>cell.Value before pre-condition</returns>
        T BeforeValue<T> (Generic.ICoCell<T> cell); 

        /// <summary>
        /// The modified source code with the pre-condition applied to the code before generation
        /// </summary>
        /// <param name="objectSource">the object name (e.g. Instrument)</param>
        /// <param name="valueSource">the value and parameters (e.g. NPV)</param>
        /// <returns>the moded source (e.g. (with :?> IPreCell).BeforeValue(Instrument).NPV</returns>
        string BeforeSource (string objectSource, string valueSource);
    }

    /// <summary>
    /// provide an interface for post-conditions to the evaluation of a cell
    /// </summary>
    public interface IPostCell
    {
        /// <summary>
        /// fluent function that evaluates the value of the cell, performs post-condition,
        /// then returns the value 
        /// </summary>
        /// <typeparam name="T">type of the cell passed in</typeparam>
        /// <param name="value">the value returned from the cell</param>
        /// <returns>cell.Value before post-condition</returns>
        T AfterValue<T> (T value);

        /// <summary>
        /// The modified source code with the post condition added
        /// </summary>
        /// <param name="valueSource">the original source code (e.g. Instrument.Value.NPV)</param>
        /// <returns>the moded source code (e.g. (with :?> IPostCell).AfterValue (Instrument.Value.NPV) )</returns>
        string AfterSource (string valueSource);
    }

    /// <summary>
    /// An empty cell is an empty value that corresponds to a null, but captures dependancies for future values
    /// </summary>
    public interface ICellEmpty : ICell
    {
    }
}
